package com.zhang.controller;

import com.zhang.exception.SleepUtils;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/product")
public class RedissionController {
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 1.最简单的分布式锁
     *  a.默认有个30秒的过期时间 internalLockLeaseTime=lockWatchdogTimeout
     *  b.每隔10秒就会自动续期  internalLockLeaseTime / 3
     *  c.RedissionLock-->tryLockInnerAsync执行lua脚本
     */
    @GetMapping("lock1")
    public String lock1(){
        RLock lock = redissonClient.getLock("lock");
        //加锁，一直等到拿锁成功
        lock.lock();
        String uuid = UUID.randomUUID().toString();
        try {
            SleepUtils.sleep(3);
            System.out.println(Thread.currentThread().getName()+"执行业务"+uuid);
        } finally {
            lock.unlock();
        }
        return Thread.currentThread().getName()+":"+uuid;
    }

    @GetMapping("lock2")
    public String lock2(){
        RLock lock = redissonClient.getLock("lock");
        //加锁以后15秒钟自动解锁，无需调用unluck方法手动解锁
        lock.lock(15, TimeUnit.SECONDS);
        String uuid = UUID.randomUUID().toString();
        try {
            SleepUtils.sleep(3);
            System.out.println(Thread.currentThread().getName()+"执行业务"+uuid);
        } finally {
            //这个代码无需调用
            lock.unlock();
        }
        return Thread.currentThread().getName()+":"+uuid;
    }

    @GetMapping("lock")
    public String lock(){
        RLock lock = redissonClient.getLock("lock");
        String uuid = UUID.randomUUID().toString();
        try {
            //尝试加锁，最多等待100秒，上锁以后10秒自动解锁
            boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
            SleepUtils.sleep(3);
            System.out.println(Thread.currentThread().getName()+"执行业务"+uuid);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //这个代码无需调用
            //lock.unlock();
        }
        return Thread.currentThread().getName()+":"+uuid;
    }

    //测试写锁
    public String uuid="";
    @GetMapping("write")
    public String write(){
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
        RLock writeLock = rwLock.writeLock();
        try {
            writeLock.lock();
            uuid = UUID.randomUUID().toString();
            SleepUtils.sleep(15);
            System.out.println(Thread.currentThread().getName()+"执行业务"+uuid);
        } finally{
            writeLock.unlock();
        }
        return Thread.currentThread().getName()+":"+uuid;
    }

    //测试读锁
    @GetMapping("read")
    public String read(){
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
        RLock readLock = rwLock.readLock();
        try {
            readLock.lock();
            return uuid;
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 测试Semaphore
     * 停车场5个
     * a.占用车位
     * b.开走 释放
     */
    @GetMapping("park")
    public String park() throws Exception{
        RSemaphore parkStation = redissonClient.getSemaphore("park_station");
        //停进车，信号量减一
        parkStation.acquire(1);
        System.out.println(Thread.currentThread().getName()+"找到车位");
        return Thread.currentThread().getName()+"找到车位";
    }

    //先离开再找车位
    @GetMapping("left")
    public String left() throws Exception{
        RSemaphore parkStation = redissonClient.getSemaphore("park_station");
        //车开走，信号量加一
        parkStation.release(1);
        System.out.println(Thread.currentThread().getName()+"left");
        return Thread.currentThread().getName()+"left";
    }

    @GetMapping("leftClassRoom")
    public String leftClassRoom() throws Exception{
        RCountDownLatch leftClassroom = redissonClient.getCountDownLatch("left_classroom");
        //有人走了 数量减一
        leftClassroom.countDown();
        return Thread.currentThread().getName()+"学员离开";
    }

    @GetMapping("lockDoor")
    public String lockDoor() throws Exception{
        RCountDownLatch leftClassroom = redissonClient.getCountDownLatch("left_classroom");
        //告知有多少人离开
        leftClassroom.trySetCount(6);
        leftClassroom.await();
        return Thread.currentThread().getName()+"班长离开";
    }
}
